﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

using TFSAdministrationTool.Controllers;
using TFSAdministrationTool.Properties;
using TFSAdministrationTool.Proxy;
using TFSAdministrationTool.Proxy.Common;
#endregion

namespace TFSAdministrationTool
{
  public partial class mainForm : Form
  {
    #region Variables
    private Icon userIcon = new Icon(Resources.User, new Size(16,16));
    private Icon addedUserIcon = new Icon(Resources.User_Added, new Size(16, 16));
    private Icon deletedUserIcon = new Icon(Resources.User_Deleted, new Size(16, 16));
    private Icon dirtyUserIcon = new Icon(Resources.User_Edited, new Size(16, 16));

    private Color defaultNodeBackground = Color.White;
    private Color selectedNodeBackground = Color.LightGray;
    private Color errorCellColor = Color.Salmon;
    private Color missingCellColor = Color.DarkGray;
    private TreeNode highlightedNode;
    #endregion

    #region Constructor
    public mainForm()
    {
      InitializeComponent();
    }
    #endregion

    #region MainForm Event Handlers
    private void MainForm_Load(object sender, EventArgs e)
    {
      try
      {
        this.Icon = Resources.App;

        mainTabControlImageList.Images.Add("PendingChanges", Resources.pendingchangesTab);
        mainTabControlImageList.Images.Add("History", Resources.historyTab);
        mainTabControlImageList.Images.Add("Output", Resources.outputTab);

        serverTreeViewImageList.Images.Add("ServerNode", Resources.server);
        serverTreeViewImageList.Images.Add("ProjectLeaf", Resources.teamproject);

        historyListViewImageList.Images.Add("Passed", Resources.passed);
        historyListViewImageList.Images.Add("Failed", Resources.failed);

        TfsAdminToolTracer.Initialize(outputTextBox);
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceVerbose, "TFS Admin Tool application started");
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
      TfsAdminToolTracer.Destroy();
    }
    #endregion

    #region TreeView ToolStrip Event Handlers
    private void serverConnectToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Server Explorere CONNECT");

        // Connect to the selected server
        StartTask(Resources.ServerConnectStatusPrompt);

        ServerInfo si = MainController.OnServerConnect(TeamFoundationServerProxyFactory.CreateTeamFoundationServerProxy());

        if(si != null)
        {
            StartTask(Resources.LoadingProjectInfoStatusPrompt);
            TreeViewAddServer(si);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    /// <summary>
    /// Disconnects the selected server 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void serverDisconnectToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Server Explorere DISCONNECT");

        string serverName;
        if ((ItemType)serverTreeView.SelectedNode.Tag ==  ItemType.Server)
        {
          serverName = serverTreeView.SelectedNode.Text;
        }
        else
        {        
          serverName = serverTreeView.SelectedNode.Parent.Text;
        }

        // In the case the server has some pending changes we should display a warning
        if (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count == 0 ||
           (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count > 0 &&
            MessageBox.Show(Resources.PendingChangesExistsPrompt, Resources.WarningCaption, MessageBoxButtons.YesNo) == DialogResult.Yes))
        {
          StartTask(Resources.ServerDisconnectStatusPrompt);

          // Disable the DataGridView
          if (String.Compare(serverName, MainController.CurrentServer.ServerName) == 0) DataGridViewEnabled(false);

          /// Remove the node from the TreeView
          TreeViewRemoveServer(serverName);

          /// Delete the server from the collection
          MainController.OnServerDisconnect(serverName, (serverTreeView.SelectedNode != null) ? serverTreeView.SelectedNode.Text : String.Empty);

          TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Successfully disconnected from Team Foundation Server - " + serverName);

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    private void serverRefreshToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Server Explorere REFRESH");

        string serverName;
        if ((ItemType)serverTreeView.SelectedNode.Tag == ItemType.Server)
        {
          serverName = serverTreeView.SelectedNode.Text;
        }
        else
        {
          serverName = serverTreeView.SelectedNode.Parent.Text;
        }

        // In the case the server has some pending changes we should display a warning
        if (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count == 0 ||
           (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count > 0 &&
            MessageBox.Show(Resources.PendingChangesExistsPrompt, Resources.WarningCaption, MessageBoxButtons.YesNo) == DialogResult.Yes))
        {
          StartTask(Resources.RefreshServerListStatusPrompt);

          // Disable the DataGridView
          if (String.Compare(serverName, MainController.CurrentServer.ServerName) == 0) DataGridViewEnabled(false);

          /// Delete the pending changes
          MainController.PendingChanges.All.Clear();

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);

          // Rerfresh the project list for the current server
          TreeViewAddServer(MainController.OnServerRefresh());
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }
    #endregion

    #region TreeView Event Handlers
    private void serverTreeView_DoubleClick(object sender, EventArgs e)
    {
      try
      {
        string serverName;
        if ((ItemType)serverTreeView.SelectedNode.Tag == ItemType.Server)
        {
          serverName = serverTreeView.SelectedNode.Text;
        }
        else
        {
          serverName = serverTreeView.SelectedNode.Parent.Text;
        }

        // In the case the server has some pending changes we should display a warning
        if (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count == 0 ||
           (MainController.PendingChanges.GetPendingChangesForServer(serverName).Count > 0 &&
            MessageBox.Show(Resources.PendingChangesExistsPrompt, Resources.WarningCaption, MessageBoxButtons.YesNo) == DialogResult.Yes))
        {
          StartTask(Resources.LoadingUserInfoStatusPrompt);

          /// Delete the pending changes
          MainController.PendingChanges.All.Clear();

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);

          /// Load user data and populate GridView
          if (LoadUserDataFromServer((ItemType)serverTreeView.SelectedNode.Tag))
          {
            // Highlight the selected node
            TreeViewHighlightNode();
          }
          else
          {
            // Restore previously slected node incase of failure
            if (highlightedNode != null)
            {
              serverTreeView.SelectedNode = highlightedNode;
            }
          }
        }
        else
        {
          // Restore previously slected node incase of failure
          if (highlightedNode != null)
          {
            serverTreeView.SelectedNode = highlightedNode;
          }
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }
    #endregion

    #region TreeView Helpers
    /// <summary>
    /// And a new Server to the TreeView or refreshes the nodes an existing one
    /// </summary>
    /// <param name="name">Name of the Server</param>
    /// <param name="list">List of child nodes</param>
    private void TreeViewAddServer(ServerInfo si)
    {
      TreeNode serverNode;

      serverTreeView.BeginUpdate();
      
      /// If server node does not exist already, create it
      if (serverTreeView.Nodes.Find(si.Name, true).Length == 0)
      {
        serverNode = new TreeNode(si.Name);
        serverNode.Name = si.Name;
        serverNode.Tag = ItemType.Server;
        serverNode.ImageIndex = 0;
        serverNode.SelectedImageIndex = 0;
        serverTreeView.Nodes.Add(serverNode);
      }
      else
      {
        serverNode = serverTreeView.Nodes.Find(si.Name, true)[0];
      }

      /// Clear the nodes of the Server node
      serverNode.Nodes.Clear();
      
      /// Add the team project to the Server node
      foreach (String projectName in si.Projects)
      {
        TreeNode projectNode = new TreeNode(projectName);
        projectNode.Tag = ItemType.TeamProject;
        projectNode.ImageIndex = 1;
        projectNode.SelectedImageIndex = 1;
        serverNode.Nodes.Add(projectNode);
      }

      serverTreeView.Sort();
      serverNode.Expand();
      serverTreeView.SelectedNode = serverNode;
      serverTreeView.Focus();
      serverTreeView.EndUpdate();

      // Make sure the treeview buttons are enabled
      TreeViewButtonsEnabled(true);
    }

    private void TreeViewRemoveServer(string name)
    {
      serverTreeView.BeginUpdate();

      serverTreeView.Nodes.RemoveByKey(name);      
      if (serverTreeView.Nodes.Count > 0)
      {
        serverTreeView.SelectedNode = serverTreeView.Nodes[0];
      }
      
      serverTreeView.EndUpdate();
    }

    private void TreeViewHighlightNode()
    {
      serverTreeView.BeginUpdate();
      if (highlightedNode != null) highlightedNode.BackColor = defaultNodeBackground;

      serverTreeView.SelectedNode.BackColor = selectedNodeBackground;
      highlightedNode = serverTreeView.SelectedNode;
      serverTreeView.EndUpdate();
    }

    private void TreeViewButtonsEnabled(bool state)
    {
      serverRefreshToolStripButton.Enabled = state;
      serverDisconnectToolStripButton.Enabled = state;
    }
    #endregion

    #region DataGrid
    private void usersDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
    {
      try
      {
        StartTask(Resources.UserEdtingStatusPrompt);
        EditSelectedUsers();
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    private void usersDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
      try
      {
        if (e.ColumnIndex < 0) return;

        TfsUser user = (TfsUser)usersDataGridView.Rows[e.RowIndex].DataBoundItem;

        // Image Column
        if (usersDataGridView.Columns[e.ColumnIndex].Name == "State")
        {
          switch (((UserState)e.Value))
          {
            case UserState.New:
              e.Value = addedUserIcon;
              break;
            case UserState.Default:
              e.Value = userIcon;
              break;
            case UserState.Deleted:
              e.Value = deletedUserIcon;
              break;
            case UserState.Edited:
              e.Value = dirtyUserIcon;
              break;
          }
        }

        // SharePoint column
        if (usersDataGridView.Columns[e.ColumnIndex].Name == "SpRoles")
        {
          // Validate the permissions of the user
          bool result = MainController.CurrentServer.RoleValidator.ValidateTfsUser(user, SystemTier.SharePoint);
          if (!result)
          {
            e.CellStyle.BackColor = errorCellColor;
          }
          else
          {
            if (MainController.CurrentServer.SharePointProxy.SiteStatus != SiteStatus.Available)
              e.CellStyle.BackColor = missingCellColor;
          }
          TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Validating user:" + user.UserName + " against SharePoint mappings. Result:" + result);
        }

        // Reporting Services column
        if (usersDataGridView.Columns[e.ColumnIndex].Name == "RsRoles")
        {
          bool result = MainController.CurrentServer.RoleValidator.ValidateTfsUser(user, SystemTier.ReportingServices);
          if (!result)
          {
            e.CellStyle.BackColor = errorCellColor;
          }
          else
          {
            if (MainController.CurrentServer.ReportServiceProxy.SiteStatus != SiteStatus.Available)
              e.CellStyle.BackColor = missingCellColor;
          }
          TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Validating user:" + user.UserName + " against Reporting Services mappings. Result:" + result);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }
    
    private void DataGridViewRender(List<TfsUser> users)
    {
      usersBindingSource.DataSource = users;
      usersBindingSource.CurrencyManager.Refresh();

      // Enable the DataGridView
      DataGridViewEnabled(true);
    }

    private void DataGridViewEnabled(bool state)
    {
      usersDataGridView.Visible = state;

      usersAddToolStripButton.Enabled = state;
      usersEditToolStripButton.Enabled = state;
      usersDeleteToolStripButton.Enabled = state;
      usersRefreshStripButton.Enabled = state;
    }
    #endregion

    #region DataGrid ToolStrip Event Handlers
    private void usersAddToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Users list ADD");
        
        UserConfiguration dlgConfigUsers = new UserConfiguration(MainController.CurrentServer);
        if (dlgConfigUsers.ShowDialog() == DialogResult.OK)
        {
          // This is where Magic happens
          List<TfsUser> mergedUsers = MainController.OnUserEditCompleted(UserConfigurationController.Users);

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);

          // Refresh the list of users
          DataGridViewRender(mergedUsers);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void usersEditToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Users list EDIT");

        StartTask(Resources.UserEdtingStatusPrompt);
        EditSelectedUsers();
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    private void usersDeleteToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Users list DELETE");
        
        List<TfsUser> selectedUsers = new List<TfsUser>();
        List<string> invalidUsers = new List<string>();

        /// Loop through the selected rows
        /// We cannot delete a user if:
        ///   - User is marked for deletion
        ///   - User has pending change
        ///   
        ///   - User is the TFSSERVICE account
        ///   - User is a Team Foundation Administrator and it is the user who is running the tool
        foreach (DataGridViewRow row in usersDataGridView.SelectedRows)
        {
          TfsUser user = TfsUser.Clone((TfsUser)row.DataBoundItem);

          if ((user.State == UserState.Deleted) || // User is marked for deletion
              (user.State == UserState.Edited) ||  // User has pending changes
              (MainController.CurrentServer.SelectedItemType == ItemType.Server && MainController.CurrentServer.IsUserServiceAccount(user)) || // User is the Service Account
              (MainController.CurrentServer.SelectedItemType == ItemType.Server && TfsUser.IsCurrentUser(user) && MainController.CurrentServer.IsUserTeamFoundationAdministrator(user))) // Current user from Team Foundation Administrators group
          {
            invalidUsers.Add(user.UserName);
          }
          else
          {
            selectedUsers.Add(user);
          }
        }
        if (invalidUsers.Count > 0)
        {
          MessageBox.Show(Resources.UsersGridDeleteWarningMessage.Replace("{0}", String.Join(",", invalidUsers.ToArray())), "Warning", MessageBoxButtons.OK);
        }
        
        if (selectedUsers.Count > 0)
        {
          /// Perform the Magic
          List<TfsUser> mergedUsers = MainController.OnDeleteUser(selectedUsers);

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);

          // Refresh the Grid
          DataGridViewRender(mergedUsers);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void usersRefreshStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Users list REFRESH");

        StartTask(Resources.LoadingUserInfoStatusPrompt);

        /// Load user data and populate GridView
        LoadUserDataFromServer((ItemType)highlightedNode.Tag);
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    private void aboutToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        AboutBox about = new AboutBox();
        about.StartPosition = FormStartPosition.CenterParent;
        about.ShowDialog();
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }
    #endregion

    #region Pending Changes Tab
    private void lvPendingChanges_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
      try
      {
        MainController.PendingChanges.UpdateSelected(new Guid(e.Item.Name), e.IsSelected);

        if (pendingChangesListView.SelectedItems.Count > 0)
        {
          pendingChangesUndoToolStripButton.Enabled = true;
        }
        else
        {
          pendingChangesUndoToolStripButton.Enabled = false;
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void pendingChangesListView_Leave(object sender, EventArgs e)
    {
      try
      {
        foreach (ListViewItem item in pendingChangesListView.Items)
        {
          item.Selected = false;
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void lvPendingChanges_ItemChecked(object sender, ItemCheckedEventArgs e)
    {
      try
      {
        MainController.PendingChanges.UpdateChecked(new Guid(e.Item.Name), e.Item.Checked);
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void pendingChangesCommitToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Pending Changes COMMIT");

        // Do we have at least one checked item
        if (MainController.PendingChanges.Checked.Count > 0)
        {
          bool isDirty = false;

          foreach (Guid guid in MainController.PendingChanges.Checked.Keys)
          {
            PendingChange pendingChange = MainController.PendingChanges.Item(guid);

            /// Build the status message
            string statusMessage = (pendingChange.ChangeType == ChangeType.Add) ? Resources.PendingChangeActionAdd : Resources.PendingChangeActionDelete + " ";
            statusMessage = statusMessage + pendingChange.UserName + " - " + pendingChange.TeamProject + " - " + pendingChange.Role;
            StartTask(statusMessage);

            /// Perform the Task Using the Controller
            Status status = MainController.OnCommitChange(pendingChange);
            
            /// Add the item to the History
            MainController.OnHistoryItemAdd(pendingChange.UserName,
                       pendingChange.DisplayName,
                       pendingChange.ChangeType,
                       pendingChange.Server,
                       pendingChange.TeamProject,
                       pendingChange.Tier,
                       pendingChange.Role,
                       status);

            if (status == Status.Passed)
            {
              isDirty = true;
              /// Remove the item from the Pending Changes object
              MainController.PendingChanges.Remove(guid);
            }
          }

          /// Append the newly added Pending Changes to the ListView
          PendingChangesDataBind(MainController.PendingChanges);

          /// Append the newly added History items
          HistoryDataBind();

          if (isDirty)
          {
            StartTask(Resources.LoadingUserInfoStatusPrompt);

            /// Refresh the Grid if any changes were successfully commited
            LoadUserDataFromServer((ItemType)highlightedNode.Tag);
          }
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      finally
      {
        EndTask();
      }
    }

    private void pendingChangesUndoToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Pending Changes UNDO");
        
        /// Do we have at least one Selected item      
        if (MainController.PendingChanges.Selected.Count > 0)
        {
          // Perform the Undo operation
          DataGridViewRender(MainController.OnUndo());

          // Refresh the list of Pending Changes
          PendingChangesDataBind(MainController.PendingChanges);
        }
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void PendingChangesDataBind(PendingChanges pendingChanges)
    {
      pendingChangesListView.BeginUpdate();
      pendingChangesListView.Items.Clear();

      foreach (KeyValuePair<Guid, PendingChange> pendingChangesItem in pendingChanges.All)
      {
        PendingChange pendingChange = pendingChangesItem.Value;

        ListViewItem item = new ListViewItem(pendingChange.UserName);
        item.Name = pendingChangesItem.Key.ToString();
        item.SubItems.AddRange(new string[] {pendingChange.DisplayName, 
                                             pendingChange.ChangeType.ToString(), 
                                             pendingChange.Server, 
                                             pendingChange.TeamProject, 
                                             pendingChange.Tier.ToString(), 
                                             pendingChange.Role});
        item.Checked = pendingChange.Checked;
        item.Selected = pendingChange.Selected;
        pendingChangesListView.Items.Add(item);
      }
      pendingChangesListView.EndUpdate();

      // Set the button states
      if (pendingChangesListView.CheckedItems.Count == 0)
      {
        pendingChangesCommitToolStripButton.Enabled = false;        
      }
      else
      {
        pendingChangesCommitToolStripButton.Enabled = true;
      }

      pendingChangesUndoToolStripButton.Enabled = false;
    }
    #endregion

    #region History Tab
    private void historyClearToolStripButton_Click(object sender, EventArgs e)
    {
      try
      {
        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: History CLEAR");
        
        MainController.OnHistoryClear();
        historyListView.Items.Clear();
        historyClearToolStripButton.Enabled = false;
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }

    private void HistoryDataBind()
    {
      historyListView.BeginUpdate();

      foreach (HistoryItem historyItem in MainController.History.GetNewHistoryItems())
      {
        ListViewItem item = new ListViewItem(historyItem.UserName);
        item.ImageIndex = (historyItem.Status == Status.Passed) ? 0 : 1;
        item.SubItems.AddRange(new string[] {historyItem.DisplayName,
                                            historyItem.ChangeType.ToString(),
                                            DateTime.Now.ToString(), 
                                            historyItem.Server,
                                            historyItem.TeamProject,
                                            historyItem.Tier.ToString(),
                                            historyItem.Role,
                                            historyItem.Status.ToString()});
        historyListView.Items.Add(item);
      }

      historyListView.EndUpdate();

      // Set the state of the button
      if (historyListView.Items.Count > 0)
      {
        historyClearToolStripButton.Enabled = true;
      }
    }
    #endregion

    #region Output Tab
    private void outputClearToolStripButton_Click(object sender, EventArgs e)
    {      
      try
      {
        outputTextBox.Clear();

        TfsAdminToolTracer.TraceMessage(TfsAdminToolTracer.TraceSwitch.TraceInfo, "Button clicked: Output CLEAR");
      }
      catch (Exception ex)
      {
        TfsAdminToolTracer.TraceException(TfsAdminToolTracer.TraceSwitch.TraceError, ex);
        MessageBox.Show(this, Resources.UnexpectedExceptionPrompt, Resources.UnexpectedExceptionCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }
    #endregion

    #region Helpers
    private void EditSelectedUsers()
    {      
      List<TfsUser> selectedUsers = new List<TfsUser>();
      List<string> invalidUsers = new List<string>();

      foreach (DataGridViewRow row in usersDataGridView.SelectedRows)
      {
        TfsUser user = TfsUser.Clone((TfsUser)row.DataBoundItem);

        // We should not allow editing: 
        //   - Users that are marked for deletion 
        //   - Users that is part of the Service 
        if ((user.State == UserState.Deleted) || // User is marked for deletion
            (MainController.CurrentServer.SelectedItemType == ItemType.Server && MainController.CurrentServer.IsUserServiceAccount(user)) || // User is the Service Account
            (MainController.CurrentServer.SelectedItemType == ItemType.Server && TfsUser.IsCurrentUser(user) && MainController.CurrentServer.IsUserTeamFoundationAdministrator(user))) // Current user from Team Foundation Administrators group  
        {
          invalidUsers.Add(user.UserName);
        }
        else
        {
          selectedUsers.Add(user);
        }
      }

      if (invalidUsers.Count > 0)
      {
        MessageBox.Show(Resources.UsersGridEditWarningMessage.Replace("{0}", String.Join(",", invalidUsers.ToArray())), "Warning", MessageBoxButtons.OK);
      }

      // This is necessary as there is a chance that the selected user
      // is marked for deletion. If so the user cannot be edited.
      if (selectedUsers.Count > 0)
      {
        UserConfiguration dlgConfigUsers = new UserConfiguration(MainController.CurrentServer, selectedUsers);
        if (dlgConfigUsers.ShowDialog() == DialogResult.OK)
        {
          // This is where Magic happens
          List<TfsUser> mergedUsers = MainController.OnUserEditCompleted(UserConfigurationController.Users);

          // Refresh the list of pending changes
          PendingChangesDataBind(MainController.PendingChanges);

          // Refresh the list of users
          DataGridViewRender(mergedUsers);
        }
      }

      EndTask();
    }

    private bool LoadUserDataFromServer(ItemType nodeType)
    {
      // Get the users with the roles
      if (nodeType == ItemType.Server)
      {
        // Server level users
        DataGridViewRender(MainController.OnServerSelected(serverTreeView.SelectedNode.Text));
      }
      else
      {
        List<TfsUser> users = MainController.OnTeamProjectSelected(serverTreeView.SelectedNode.Parent.Text, serverTreeView.SelectedNode.Text);

        SiteStatus spStatus = MainController.CurrentServer.SharePointProxy.SiteStatus;
        SiteStatus rsStatus = MainController.CurrentServer.ReportServiceProxy.SiteStatus;

        string msg = (spStatus != SiteStatus.Available) ? "SharePoint" : "";
        msg += (spStatus != SiteStatus.Available && rsStatus != SiteStatus.Available) ? " & " : "";
        msg += (rsStatus != SiteStatus.Available) ? "ReportServer" : "";

        if (spStatus == SiteStatus.Unauthorized || rsStatus == SiteStatus.Unauthorized)
        {
          MessageBox.Show(string.Format(Resources.UnauthorizedTierConnection, msg), string.Format(Resources.UnauthorizedTier, msg), MessageBoxButtons.OK, MessageBoxIcon.Error);
          return false;
        }
        else if (spStatus == SiteStatus.Error || rsStatus == SiteStatus.Error)
        {
          MessageBox.Show(string.Format(Resources.ErrorTierConnection, msg), string.Format(Resources.ErrorTier, msg), MessageBoxButtons.OK, MessageBoxIcon.Error);
          return false;
        }
        else if (spStatus == SiteStatus.Unavailable || rsStatus == SiteStatus.Unavailable)
        {
          MessageBox.Show(string.Format(Resources.MissingTierConnection, msg), string.Format(Resources.MissingTier, msg), MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        DataGridViewRender(users);
      }

      return true;
    }
    
    private void StartTask(string task)
    {
      toolStripStatusLabel.Text = task;
      this.Cursor = Cursors.WaitCursor;
      Application.DoEvents();    
    }

    private void EndTask()
    {
      toolStripStatusLabel.Text = Resources.TaskDoneStatusPrompt;
      this.Cursor = Cursors.Default;
    }
    #endregion
  } //End Class
} //End Namespace